package model.simulationmodel.logicelements;

import model.editormodel.Input;
import model.editormodel.LogicEditorElement;
import model.editormodel.Output;
import model.simulationmodel.LogicValue;
import model.simulationmodel.SimulationModel;

/**
 * <b>Erbt:</b> <code>LogicSimulationElement</code> <br>
 * <b>Funktion:</b> Umsetzung der Logik eines FlipFlops<br>
 * <b>Logik:</b> s = Eingang1, r = Eingang2, q = Ausgang1, nq = Ausgang2 <br>
 * s | r || q | nq <br>
 * ------------<br>
 * 1 | 1 || 1 | 1 instabil <br>
 * 1 | 0 || 1 | 0 zurueckgesetzt<br>
 * 0 | 1 || 0 | 1 gesetzt<br>
 * 0 | 0 || unveraendert <br>
 * ... <br>
 * Repraesentiert ein RS - FlipFlop. Ist das FlipFlop instabil, wird ein
 * <code>UNDEFINED</code> als Wert propagiert.
 * 
 * @author Team Locsi
 * 
 */
public class LogicFLIPFLOP extends LogicSimulationElement {

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>LogicFLIPFLOP</code>-Objekt.
	 * 
	 * @param sModel
	 *            <code>SimulationModel</code> - Referenz auf das
	 *            <code>SimulationModel</code>
	 * @param logicEditorElement
	 *            <code>LogicEditorElement</code> - Referenz auf das zugehoerige
	 *            <code>LogicEditorElement</code>
	 */
	public LogicFLIPFLOP(SimulationModel sModel,
			LogicEditorElement logicEditorElement) {
		super(sModel, logicEditorElement);
	}

	@Override
	public void calcLogicValue() {

		// zu berechnende Ausgaenge
		LogicValue ffQ = LogicValue.UNDEFINED;
		LogicValue ffNq = LogicValue.UNDEFINED;

		// eingangswerte holen
		LogicValue ffSet = logicInputValueMap.get(Input.FF_SET);
		LogicValue ffReset = logicInputValueMap.get(Input.FF_RESET);

		// Berechnung des FlipFlops
		// falls beide Eingänge L0 sind wird nichts verändert!!
		if (!(ffSet == LogicValue.L0 && ffReset == LogicValue.L0)) {
			if (ffSet == LogicValue.L1) {
				if (ffReset == LogicValue.L1) {
					ffQ = LogicValue.L1;
					ffNq = LogicValue.L1;
				} else if (ffReset == LogicValue.L0) {
					ffQ = LogicValue.L1;
					ffNq = LogicValue.L0;
				} else if (ffReset == LogicValue.UNDEFINED) {
					ffQ = LogicValue.L1;
				}
			} else if (ffSet == LogicValue.L0) {
				if (ffReset == LogicValue.L1) {
					ffQ = LogicValue.L0;
					ffNq = LogicValue.L1;
				}
			} else if (ffSet == LogicValue.UNDEFINED) {
				if (ffReset == LogicValue.L1) {
					ffNq = LogicValue.L1;
				}
			}

			// Ausgaenge werden nur gesetzt wenn sich an ihnen was veraendert
			if (ffQ != logicOutputValueMap.get(Output.FF_Q)) {
				this.setOutputValue(Output.FF_Q, ffQ);
			}
			if (ffNq != logicOutputValueMap.get(Output.FF_NQ)) {
				this.setOutputValue(Output.FF_NQ, ffNq);
			}
		}
	}
}